package lac.serviceuint;

import java.io.InputStream;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import lac.model.core.persistent.Session;
import lac.model.core.persistent.SessionFactory;
import lac.model.core.persistent.criterion.Criteria;
import lac.model.core.persistent.criterion.Order;
import lac.serviceuint.job.JobHandle;
import lac.serviceuint.job.JobInterceptor;
import lac.serviceuint.job.cfg.ServiceUnitJob;
import lac.serviceuint.job.model.ServiceUnitJobModelDescribe;
import lac.serviceuint.job.quartz.ServiceUnitJobBuilder;
import lac.serviceuint.job.quartz.ServiceUnitJobFactory;
import lac.serviceuint.tool.ApplicationContextBean;

public class ServiceUnitJobScheduler {

	private static Logger log = LoggerFactory.getLogger(ServiceUnitJobScheduler.class);
	
	@Autowired(required=false)
	private SessionFactory sessionFactory;
	@Autowired(required=false)
	private ServiceUnitExecuter serviceUnitExecuter;
	
	private Scheduler scheduler;
	
	private Map<String,ServiceUnitJob> serviceUnitJobContext = new LinkedHashMap<>();
	
	private List<JobInterceptor> jobiInterceptors;
	
	public ServiceUnitJob getServiceUnitJob(InputStream inputStream){
		return (ServiceUnitJob) ServiceUnitContext.xstream.fromXML(inputStream);
	}
	
	public void addJob(InputStream inputStream) throws Exception{
		ServiceUnitJob serviceUnitJob= getServiceUnitJob(inputStream);
		addJob(serviceUnitJob);
	}
	
	public void addJob(ServiceUnitJob serviceUnitJob) throws Exception{
		log.info("加载ServiceUnitJob:"+serviceUnitJob.getName());
		if(serviceUnitJob.getEnable()){
			scheduler.scheduleJob(getJobDetail(serviceUnitJob), getTriggers(serviceUnitJob),true);
			serviceUnitJobContext.put(serviceUnitJob.getName(), serviceUnitJob);
		}
		
	}
	
	private JobDetail getJobDetail(ServiceUnitJob serviceUnitJob){
		JobHandle jobHandle =  new JobHandle(serviceUnitJob);
		jobHandle.addTaskInterceptor(jobiInterceptors);
		jobHandle.setServiceUnitExecuter(serviceUnitExecuter);
		JobDetail job = ServiceUnitJobBuilder.newJob().setJob(jobHandle)
			    .withIdentity(new JobKey(serviceUnitJob.getName(), serviceUnitJob.getServiceUnitName()+"_"+serviceUnitJob.getMethodName()))
			    .build();
		return job;
	}
	
	private Set<Trigger> getTriggers(ServiceUnitJob serviceUnitJob){
		Set<Trigger> triggers = new HashSet<>();
		Trigger trigger = TriggerBuilder.newTrigger()
			    .withIdentity(serviceUnitJob.getName(), serviceUnitJob.getServiceUnitName()+"_"+serviceUnitJob.getMethodName())
			    .withSchedule(CronScheduleBuilder.cronSchedule(serviceUnitJob.getCron()))
			    .build();
		triggers.add(trigger);
		return triggers;
	}
	
	public void init() throws Exception{
		//SchedulerFactory  schedulerFactory = new StdSchedulerFactory();
		scheduler = StdSchedulerFactory.getDefaultScheduler();
		scheduler.setJobFactory(new ServiceUnitJobFactory());
		//scheduler.getListenerManager().addJobListener(null);
		jobiInterceptors = ApplicationContextBean.getBeans(JobInterceptor.class);
		jobiInterceptors.sort(new Comparator<JobInterceptor>(){
			@Override
			public int compare(JobInterceptor o1, JobInterceptor o2) {
				return o1.sort()-o2.sort();
			}
		});
		log.debug("ServiceUnitJobScheduler is inited !");
	}
	
	
	public void loadJobFromDB() throws Exception{
		if(sessionFactory!=null){
			Session session = sessionFactory.getSession();
			Criteria criteria = new Criteria();
			criteria.addOrder(new Order("params.index", 1));
			List<ServiceUnitJob> ServiceUnitJobs = session.query(new ServiceUnitJobModelDescribe().getName(),criteria,ServiceUnitJob.class);
			for(ServiceUnitJob serviceUnitJob : ServiceUnitJobs){
				addJob(serviceUnitJob);
			}
			
		}
	}
	
	public void start(int delayedSeconds) throws SchedulerException{
		scheduler.startDelayed(delayedSeconds);
	}
	
	
	public ServiceUnitExecuter getServiceUnitExecuter() {
		return serviceUnitExecuter;
	}

	public void setServiceUnitExecuter(ServiceUnitExecuter serviceUnitExecuter) {
		this.serviceUnitExecuter = serviceUnitExecuter;
	}

	public Map<String, ServiceUnitJob> getServiceUnitJobContext() {
		return serviceUnitJobContext;
	}

	public void setServiceUnitJobContext(Map<String, ServiceUnitJob> serviceUnitJobContext) {
		this.serviceUnitJobContext = serviceUnitJobContext;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Scheduler getScheduler() {
		return scheduler;
	}

	/*public static void main(String[] args) {
		try {
			ServiceUnitJobScheduler scheduler = new ServiceUnitJobScheduler();
			scheduler.init();
			
			ServiceUnitJob  serviceUnitJob1= new ServiceUnitJob();
			serviceUnitJob1.setCron("0/10 * * * * ?");
			serviceUnitJob1.setName("abc");
			serviceUnitJob1.setServiceUnitName("service1");
			serviceUnitJob1.setMethodName("metod1");
			List<JobParam> params = new ArrayList<JobParam>();
			params.add(new JobParam("d", "String", 4, "d"));
			params.add(new JobParam("a", "String", 1, "a"));
			params.add(new JobParam("e", "String", 6, "e"));
			params.add(new JobParam("b", "String", 9, "b"));
			params.add(new JobParam("c", "String", 3, "c"));
			serviceUnitJob1.setParams(params);
			
			
			scheduler.addJob(serviceUnitJob1);
			
			scheduler.start();
			
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}*/
	
}
